use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use std::thread::Thread;

use crate::class_file::byte_data_reader::ByteDataReader;
use crate::instruction::add::{iadd, ladd};
use crate::instruction::arraylength::arraylength;
use crate::instruction::const_instruction::{iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5, iconst_m1, lconst_0, lconst_1};
use crate::instruction::convert::{d2f, d2i, d2l, i2b, i2c, i2d, i2f, i2l, i2s};
use crate::instruction::dconst::{dconst_0, dconst_1};
use crate::instruction::dup::dup;
use crate::instruction::fconst::{fconst_0, fconst_1, fconst_2};
use crate::instruction::getfield::getfield;
use crate::instruction::getstatic::getstatic;
use crate::instruction::goto::goto;
use crate::instruction::invoke::invoke_native;
use crate::instruction::invokespecial::invokespecial;
use crate::instruction::invokestatic::invokestatic;
use crate::instruction::invokevirtual::invokevirtual;
use crate::instruction::ldc::{ldc, ldc2_w};
use crate::instruction::load::{aaload, aload, aload_0, aload_1, aload_2, aload_3, baload, caload, daload, dload_0, dload_1, dload_2, dload_3, faload, iaload, iload_0, iload_1, iload_2, iload_3, laload, lload_0, lload_1, lload_2, lload_3, saload};
use crate::instruction::new::{anewarray, new, newarray};
use crate::instruction::push::{bipush, sipush};
use crate::instruction::putfield::putfield;
use crate::instruction::putstatic::putstatic;
use crate::instruction::r#if::{if_icmpeq, if_icmpge, if_icmpgt, if_icmple, if_icmplt, if_icmpne, ifeq, ifge, ifgt, ifle, iflt, ifne, ifnonnull};
use crate::instruction::r#return::{ireturn, vreturn, areturn};
use crate::instruction::shift::ishr;
use crate::instruction::store::{aastore, astore, astore_0, astore_1, astore_2, astore_3, bastore, castore, dastore, fastore, iastore, istore_0, istore_1, istore_2, istore_3, lastore, lstore_0, lstore_1, lstore_2, lstore_3, sastore};
use crate::vm_thread::{VMFrame, VMThread};

pub trait Instruction {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {}

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread);

    fn to_string(&self) -> String {
        String::from("Instruction")
    }
}


const ICONST_M1: iconst_m1 = iconst_m1 {};
const ICONST_0: iconst_0 = iconst_0 {};
const ICONST_1: iconst_1 = iconst_1 {};
const ICONST_2: iconst_2 = iconst_2 {};
const ICONST_3: iconst_3 = iconst_3 {};
const ICONST_4: iconst_4 = iconst_4 {};
const ICONST_5: iconst_5 = iconst_5 {};


const LCONST_0: lconst_0 = lconst_0 {};
const LCONST_1: lconst_1 = lconst_1 {};

const FLOAD_0: fconst_0 = fconst_0 {};
const FLOAD_1: fconst_1 = fconst_1 {};
const FLOAD_2: fconst_2 = fconst_2 {};

const DCONST_0: dconst_0 = dconst_0 {};
const DCONST_1: dconst_1 = dconst_1 {};


const CALOAD: caload = caload {};

const DLOAD_0: dload_0 = dload_0 {};
const DLOAD_1: dload_1 = dload_1 {};
const DLOAD_2: dload_2 = dload_2 {};
const DLOAD_3: dload_3 = dload_3 {};

const ILOAD_0: iload_0 = iload_0 {};
const ILOAD_1: iload_1 = iload_1 {};
const ILOAD_2: iload_2 = iload_2 {};
const ILOAD_3: iload_3 = iload_3 {};


const LLOAD_0: lload_0 = lload_0 {};
const LLOAD_1: lload_1 = lload_1 {};
const LLOAD_2: lload_2 = lload_2 {};
const LLOAD_3: lload_3 = lload_3 {};

const ALOAD_0: aload_0 = aload_0 {};
const ALOAD_1: aload_1 = aload_1 {};
const ALOAD_2: aload_2 = aload_2 {};
const ALOAD_3: aload_3 = aload_3 {};

const IALOAD: iaload = iaload {};
const LALOAD: laload = laload {};
const FALOAD: faload = faload {};
const DALOAD: daload = daload {};
const BALOAD: baload = baload {};
const SALOAD: saload = saload {};
const AALOAD: aaload = aaload {};

const ISTORE_0: istore_0 = istore_0 {};
const ISTORE_1: istore_1 = istore_1 {};
const ISTORE_2: istore_2 = istore_2 {};
const ISTORE_3: istore_3 = istore_3 {};

const LSTORE_0: lstore_0 = lstore_0 {};
const LSTORE_1: lstore_1 = lstore_1 {};
const LSTORE_2: lstore_2 = lstore_2 {};
const LSTORE_3: lstore_3 = lstore_3 {};

const CASTORE: castore = castore {};

const ASTORE_0: astore_0 = astore_0 {};
const ASTORE_1: astore_1 = astore_1 {};
const ASTORE_2: astore_2 = astore_2 {};
const ASTORE_3: astore_3 = astore_3 {};

const BASTORE: bastore = bastore {};
const SASTORE: sastore = sastore {};
const IASTORE: iastore = iastore {};
const LASTORE: lastore = lastore {};
const FASTORE: fastore = fastore {};
const DASTORE: dastore = dastore {};
const AASTORE: aastore = aastore {};

const DUP: dup = dup {};

const IADD: iadd = iadd {};
const LADD: ladd = ladd {};

const IRETURN: ireturn = ireturn {};
const ARETURN: areturn = areturn {};
const VRETURN: vreturn = vreturn {};

const ARRAY_LENGTH: arraylength = arraylength {};

const ISHR: ishr = ishr {};

const I2B: i2b = i2b {};
const I2C: i2c = i2c {};
const I2D: i2d = i2d {};
const I2F: i2f = i2f {};
const I2L: i2l = i2l {};
const I2S: i2s = i2s {};

const D2F: d2f = d2f {};
const D2I: d2i = d2i {};
const D2L: d2l = d2l {};

pub struct InstructionFactory {}

impl InstructionFactory {
    pub fn create_instruction(opcode: u8) -> Box<dyn Instruction> {
        match opcode {
            0x02 => { Box::new(ICONST_M1) }
            0x03 => { Box::new(ICONST_0) }
            0x04 => { Box::new(ICONST_1) }
            0x05 => { Box::new(ICONST_2) }
            0x06 => { Box::new(ICONST_3) }
            0x07 => { Box::new(ICONST_4) }
            0x08 => { Box::new(ICONST_5) }
            0x09 => { Box::new(LCONST_0) }
            0x0a => { Box::new(LCONST_1) }
            0x0b => { Box::new(FLOAD_0) }
            0x0c => { Box::new(FLOAD_1) }
            0x0d => { Box::new(FLOAD_2) }
            0x0e => { Box::new(DCONST_0) }
            0x0f => { Box::new(DCONST_1) }
            0x10 => { Box::new(bipush { val: 0 }) }
            0x11 => { Box::new(sipush { val: 0 }) }
            0x12 => { Box::new(ldc { index: 0 }) }
            0x14 => { Box::new(ldc2_w { index: 0 }) }
            0x19 => { Box::new(aload { index: 0 }) }
            0x1a => { Box::new(ILOAD_0) }
            0x1b => { Box::new(ILOAD_1) }
            0x1c => { Box::new(ILOAD_2) }
            0x1d => { Box::new(ILOAD_3) }
            0x1e => { Box::new(LLOAD_0) }
            0x1f => { Box::new(LLOAD_1) }
            0x20 => { Box::new(LLOAD_2) }
            0x21 => { Box::new(LLOAD_3) }
            0x26 => { Box::new(DLOAD_0) }
            0x27 => { Box::new(DLOAD_1) }
            0x28 => { Box::new(DLOAD_2) }
            0x29 => { Box::new(DLOAD_3) }
            0x2a => { Box::new(ALOAD_0) }
            0x2b => { Box::new(ALOAD_1) }
            0x2c => { Box::new(ALOAD_2) }
            0x2d => { Box::new(ALOAD_3) }
            0x2e => { Box::new(IALOAD) }
            0x2f => { Box::new(LALOAD) }
            0x30 => { Box::new(FALOAD) }
            0x31 => { Box::new(DALOAD) }
            0x32 => { Box::new(AALOAD) }
            0x33 => { Box::new(BALOAD) }
            0x34 => { Box::new(CALOAD) }
            0x35 => { Box::new(SALOAD) }
            0x3a => { Box::new(astore { index: 0 }) }
            0x3b => { Box::new(ISTORE_0) }
            0x3c => { Box::new(ISTORE_1) }
            0x3d => { Box::new(ISTORE_2) }
            0x3e => { Box::new(ISTORE_3) }
            0x3f => { Box::new(LSTORE_0) }
            0x40 => { Box::new(LSTORE_1) }
            0x41 => { Box::new(LSTORE_2) }
            0x42 => { Box::new(LSTORE_3) }
            0x4b => { Box::new(ASTORE_0) }
            0x4c => { Box::new(ASTORE_1) }
            0x4d => { Box::new(ASTORE_2) }
            0x4e => { Box::new(ASTORE_3) }
            0x4f => { Box::new(IASTORE) }
            0x50 => { Box::new(LASTORE) }
            0x51 => { Box::new(FASTORE) }
            0x52 => { Box::new(DASTORE) }
            0x53 => { Box::new(AASTORE) }
            0x54 => { Box::new(BASTORE) }
            0x55 => { Box::new(CASTORE) }
            0x56 => { Box::new(SASTORE) }
            0x59 => { Box::new(DUP) }
            0x60 => { Box::new(IADD) }
            0x61 => { Box::new(LADD) }
            0x7a => { Box::new(ISHR) }
            0x85 => { Box::new(I2L) }
            0x86 => { Box::new(I2F) }
            0x87 => { Box::new(I2D) }
            0x8e => { Box::new(D2I) }
            0x8f => { Box::new(D2L) }
            0x90 => { Box::new(D2F) }
            0x91 => { Box::new(I2B) }
            0x92 => { Box::new(I2C) }
            0x93 => { Box::new(I2S) }
            0x9f => { Box::new(if_icmpeq { offset: 0 }) }
            0x99 => { Box::new(ifeq { offset: 0 }) }
            0x9a => { Box::new(ifne { offset: 0 }) }
            0x9b => { Box::new(iflt { offset: 0 }) }
            0x9c => { Box::new(ifge { offset: 0 }) }
            0x9d => { Box::new(ifgt { offset: 0 }) }
            0x9e => { Box::new(ifle { offset: 0 }) }
            0xa0 => { Box::new(if_icmpne { offset: 0 }) }
            0xa1 => { Box::new(if_icmplt { offset: 0 }) }
            0xa2 => { Box::new(if_icmpge { offset: 0 }) }
            0xa3 => { Box::new(if_icmpgt { offset: 0 }) }
            0xa4 => { Box::new(if_icmple { offset: 0 }) }
            0xa7 => { Box::new(goto { offset: 0 }) }
            0xac => { Box::new(IRETURN) }
            0xb0 => { Box::new(ARETURN) }
            0xb1 => { Box::new(VRETURN) }
            0xb2 => { Box::new(getstatic { index: 0 }) }
            0xb3 => { Box::new(putstatic { index: 0 }) }
            0xb4 => { Box::new(getfield { index: 0 }) }
            0xb5 => { Box::new(putfield { index: 0 }) }
            0xb6 => { Box::new(invokevirtual { index: 0 }) }
            0xb7 => { Box::new(invokespecial { index: 0 }) }
            0xb8 => { Box::new(invokestatic { index: 0 }) }
            0xbb => { Box::new(new { val: 0 }) }
            0xbc => { Box::new(newarray { atype: 0 }) }
            0xbd => { Box::new(anewarray { index: 0 }) }
            0xbe => { Box::new(ARRAY_LENGTH) }
            0xc7 => { Box::new(ifnonnull { offset: 0 }) }
            0xff => { Box::new(invoke_native { sub_opcode: 0 }) }
            _ => {
                panic!("{},{},异常opcode:{}", file!(), line!(), opcode);
            }
        }
    }
}